﻿namespace Simple.Utils.Helper
{
    public class LockHelper
    {
        /// <summary>
        /// 0x12fd 表示4861，可以同时有4861个key，即同时可以支持4861个线程同时运行LockRun方法
        /// </summary>
        private const int LockeCount = 0x12fd; // 素数，减少hash冲突，值越大冲突概率越小，但占用内存越大

        private static readonly int[] Locks = new int[LockeCount];

        public static event Action<string> MessageEv;

        /// <summary>以关键字锁运行方法，线程同步运行，排队执行</summary>
        /// <param name="key">关键字</param>
        /// <param name="act">方法体</param>
        /// <param name="timeOut">锁超时时间，默认0 单位秒</param>
        /// <exception cref="TimeoutException">如果线程在指定超时内未能获取锁</exception>
        public static void LockRun(string key, Action act, int timeOut = 0)
        {
            if (string.IsNullOrEmpty(key)) throw new ArgumentException("Key cannot be null or empty.", nameof(key));
            if (act == null) throw new ArgumentNullException(nameof(act));

            int index = (key.GetHashCode() & 0x7fffffff) % LockeCount;
            decimal timeCount = 0;
            SpinWait spinWait = new SpinWait();

            // 尝试进入对应index的临界状态
            while (Interlocked.CompareExchange(ref Locks[index], 1, 0) == 1)
            {
                spinWait.SpinOnce(); // 使用自旋等待

                timeCount += 0.01M;

                if (timeOut > 0 && timeCount > timeOut)
                {
                    string message = $"线程 {Thread.CurrentThread.ManagedThreadId} 获取锁【key = {key}】超时，耗时 {timeCount} s";
                    MessageEv?.Invoke(message);
                    throw new TimeoutException(message);
                }
            }

            try
            {
                string message = $"线程 {Thread.CurrentThread.ManagedThreadId} 已获取【{key}】锁，耗时 {timeCount} s，开始执行函数";
                MessageEv?.Invoke(message);
                act();
            }
            finally
            {
                Interlocked.Exchange(ref Locks[index], 0); // 释放锁
                MessageEv?.Invoke($"线程 {Thread.CurrentThread.ManagedThreadId} 【{key}】锁已释放");
            }
        }
    }
}